home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
NOVA - For the NeXT Workstation
/
NOVA - For the NeXT Workstation.iso
/
Apps
/
Utilities
/
Unix
/
Piper
/
Piper.m
< prev
next >
Wrap
Text File
|
1992-12-26
|
10KB
|
231 lines
#import <defaults/defaults.h> //for NXArgv
#import <appkit/Application.h> //for NXApp
#import <appkit/Listener.h> //for void NXUpdateDynamicServices(void)
#import <appkit/Panel.h> //for NXRunAlertPanel
#import <appkit/Pasteboard.h>
#import <libc.h> //for mktemp
#import <mach/mach.h> //vm_deallocate
#import <objc/Storage.h>
#import <stdio.h>
#import <stdlib.h>
#import <strings.h> //For strcmp
#import <sys/dir.h>
#import <sys/stat.h>
#import <sys/param.h> //For MAXPATHLEN
//Maybe not using <appkit/appkit.h> goes faster... But it's a pain spelling
//all this out. I want a CASE tool from NeXT!
#import "Piper.h"
@implementation Piper
-appDidInit:sender{
// Make us the object that service requests (piperMessage) get sent to.
[[NXApp appListener] setServicesDelegate:self];
return self;
}
-piperMessage:(id)pb userData:(const char *)userData error:(char **)msg{
/*var*/
char **pbtypes,*data,*outputData,
scriptCmd[MAXPATHLEN];
int length,err, i, outputLen, outputMaxlen;
FILE *pipe;
NXStream *pNXStream;
static char outputFile[]="/tmp/PipeXXXXXX";
struct stat sbuf;
if(!strcmp(userData,"NXUpdateDynamicServices")){
[self reloadScripts:self];
return self;
}
for(pbtypes=(char **)[pb types];*pbtypes;pbtypes++){
if( (*pbtypes==NXAsciiPboardType /*Plain ASCII text*/)||
(*pbtypes==NXFilenamePboardType /*ASCII file name */)){
[pb readType:*pbtypes data:&data length:&length];
sprintf(scriptCmd,"%s/script",userData);
stat(scriptCmd, &sbuf);
if(!(sbuf.st_mode & 0111)){
NXRunAlertPanel(NULL,"No execute permission on %s",
NULL,NULL,NULL, scriptCmd);
exit(1);
}
mktemp(outputFile);
if(0){
}else if(*pbtypes==NXAsciiPboardType){
//For ascii pasteboard types, we just read the selection
//and pipe it through the given script. The output is collected
//in a temporary file.
//I think this should become an NXStream, somehow
//(needs another thread, hmmm)!!!
sprintf(scriptCmd,"%s/script >%s 2>/dev/console",
userData,outputFile);
if((pipe=popen(scriptCmd,"w"))==NULL){
NXRunAlertPanel(NULL, "Command \"%s\" failed",
NULL,NULL,NULL,scriptCmd);
exit(1);
}
for(i=0;i<length;i++) putc(data[i], pipe);
if(err=pclose(pipe)){
NXRunAlertPanel(NULL,"Command \"%s\" returned error code %d",
NULL,NULL,NULL, userData, err);
}
}else if(*pbtypes==NXFilenamePboardType){
//Selection is a filename. Run the script with the filename
//as the only parameter. Any output is collected in the
//temporary file.
/*var*/ char *pchar;
while(pchar=data,pchar){
if(data=index(data,'\t')){ *data=0; data++; }
sprintf(scriptCmd, "%s/script \"%s\" >%s 2>/dev/console",
userData, pchar, outputFile);
if(err=system(scriptCmd)){
NXRunAlertPanel(NULL,"Command \"%s\" returned error code %d. "
"Look at Console",
NULL,NULL,NULL, userData, err);
}
}
}
//Now the fun bit. Any output from the script will be in the temporary
//file outputFile. Map the file in and paste the data out to the
//selection pasteboard.
pNXStream=NXMapFile(outputFile,NX_READONLY);
NXGetMemoryBuffer(pNXStream, &outputData, &outputLen, &outputMaxlen);
[pb declareTypes:&NXAsciiPboardType num:1 owner:self];
[pb writeType:NXAsciiPboardType data:outputData length:outputLen];
vm_deallocate(task_self(),(int)data,length);
sprintf(scriptCmd,"rm -f %s",outputFile);
system(scriptCmd);
return self;
}
}
//Didn't find one we liked (dropped out of pbtypes list).
NXRunAlertPanel(NULL,"Piper does not recognize pasteboard type %d",
NULL,NULL,NULL,*pbtypes);
return self;
}
-reloadScripts:sender{
/*var*/
int keyFound,returnFound;
struct stat stats;
char option[256],keyOption[256],returnOption[256];
FILE *lspipe,*serviceFile,*optionsFile;
/*Make serviceFile your private services cache file.*/{
/*var*/ char serviceFilePath[MAXPATHLEN];
sprintf(serviceFilePath,"%s/.NeXT/services/Piper",getenv("HOME"));
if((serviceFile=fopen(serviceFilePath,"w"))==NULL){
NXRunAlertPanel(NULL,"Could not open service file %s",
"Quit",NULL,NULL, serviceFilePath);
exit(1);
} //Shouldn't happen.
}
/*Make lspipe a pipe filled with script paths.*/{
/*var*/ char executablePath[MAXPATHLEN],
cmd [MAXPATHLEN];
if(NXArgv[0][0]=='/'){
strcpy(executablePath,NXArgv[0]); *rindex(executablePath,'/')=0;
}else{
switch(NXRunAlertPanel( NULL,
"Please don't use the Update Dynamic Services "
"command in Piper's menu if it were "
"launched "
"from a shell with a partial path if you want "
"its SampleScripts to be included. "
"Maybe some programmer will give me a tool "
"to get the full path using the notion of "
"current directory or something? "
"He might then distribute this to the NeXT "
"programming community…",
"Quit","Cancel",NULL)){
case NX_ALERTDEFAULT: [NXApp terminate:self]; //break's not necessary
case NX_ALERTALTERNATE: return self; //same
}
}
sprintf(cmd,"ls %s/SampleScripts/../SampleScripts 2>/dev/null "
"| awk '{print \"%s/SampleScripts/\"$0}' 2>/dev/null; "
"ls /LocalLibrary/Piper/../Piper 2>/dev/null "
"| awk '{print \"/LocalLibrary/Piper/\"$0}' 2>/dev/null; "
"ls %s/Library/Piper/../Piper 2>/dev/null "
"| awk '{print \"%s/Library/Piper/\"$0}' 2>/dev/null",
executablePath, executablePath,getenv("HOME"),getenv("HOME"));
if((lspipe=popen(cmd,"r"))==NULL){
NXRunAlertPanel(NULL,"lspipe could not be opened",
NULL,NULL,NULL);
exit(1);
} //If this happens, it's a bug.
}
/*Search for scripts.*/{
/*var*/ int count; //how many valid ones we found
char scriptDirPath[MAXPATHLEN],actualScriptPath[MAXPATHLEN];
for(count=0;
fgets(scriptDirPath,sizeof(scriptDirPath),lspipe)!=NULL;
count++){
scriptDirPath[strlen(scriptDirPath)-1]=0;
if(stat(scriptDirPath,&stats)<0||!(stats.st_mode&S_IFDIR)){
NXRunAlertPanel(NULL,"%s is not a directory!",
NULL,NULL,NULL,scriptDirPath);
continue;
}
sprintf(actualScriptPath,"%s/script",scriptDirPath);
if(stat(actualScriptPath,&stats)<0||!(stats.st_mode & 0111)){
NXRunAlertPanel(NULL,"%s does not exist or is not executable",
NULL,NULL,NULL,actualScriptPath);
continue;
}
fprintf(serviceFile,"Message: piperMessage\n"
"Port: Piper\n"
"Menu Item: Piper/%s\n"
"User Data: %s\n",
rindex(scriptDirPath,'/')+1,
scriptDirPath);
/*Look for options.*/{
/*var*/ char optionsPath[MAXPATHLEN];
sprintf(optionsPath,"%s/options",scriptDirPath);
keyFound=returnFound=0;
if((optionsFile=fopen(optionsPath,"r"))!=NULL){
while(fgets(option,sizeof(option),optionsFile)!=NULL){
if(!strncmp(option,"Key Equivalent",14)){
strcpy(keyOption,option);
keyFound++;
}else if(!strncmp(option,"Return Type",11)){
strcpy(returnOption, option);
returnFound++;
}else if(!strcmp(option,"Send Type: NXAsciiPboardType\n")){
fprintf(serviceFile,option);
}else if(!strcmp(option,"Send Type: NXFilenamePboardType\n")){
fprintf(serviceFile,option);
}else{
NXRunAlertPanel(NULL,"Option\n"
"%s\n"
"not recognized in script\n"
"%s",
NULL,NULL,NULL,option,scriptDirPath);
}
}
fclose(optionsFile);
}
}
if(returnFound) fprintf(serviceFile,returnOption);
if(keyFound) fprintf(serviceFile,keyOption);
/*always*/ fprintf(serviceFile,"\n");
}
pclose(lspipe);
fclose(serviceFile);
NXUpdateDynamicServices();
if(!count){
/*var*/ char somePath[MAXPATHLEN];
NXRunAlertPanel(NULL,"No valid scripts found",
NULL,NULL,NULL);
sprintf(somePath,"%s/.NeXT/services/Piper",getenv("HOME"));
if(remove(somePath))
NXRunAlertPanel(NULL,
"Also, I could not get rid of ``%s''",
NULL,NULL,NULL,somePath);
exit(1);
}
}
NXRunAlertPanel(NULL,
"Relaunch applications in which you want to use new "
"names, if you haven't got a version (3.0 at least) "
"in which NeXT fixed this.",
NULL,NULL,NULL);
return self;
}
@end